package git.soulbgm.backend;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * UDP后端服务器连接管理类
 *
 * <p>管理与后端服务器的UDP连接，处理数据包的发送和接收。
 * 维护后端服务器的连接状态和会话信息。</p>
 *
 * <p>主要功能：</p>
 * <ul>
 *   <li>建立与后端服务器的连接</li>
 *   <li>发送数据包到后端服务器</li>
 *   <li>接收后端服务器响应</li>
 *   <li>管理连接生命周期</li>
 * </ul>
 *
 * @author soulbgm
 * @version 1.0
 * @since 1.0
 */
public class UdpBackendServer {
    private static final Logger logger = LoggerFactory.getLogger(UdpBackendServer.class);

    private final int port;
    private final DatagramSocket socket;
    private final AtomicBoolean running = new AtomicBoolean(true);
    private static final byte[] HEARTBEAT_DATA = "HEARTBEAT".getBytes();
    private static final int BUFFER_SIZE = 65507;

    public UdpBackendServer(int port) throws SocketException {
        this.port = port;
        this.socket = new DatagramSocket(port);
        logger.info("UDP后端服务器启动，监听端口: {}", port);
    }

    /**
     * 启动服务器
     */
    public void start() {
        Thread serverThread = new Thread(this::run);
        serverThread.setName("UDP-Backend-" + port);
        serverThread.start();
    }

    /**
     * 服务器主循环
     */
    private void run() {
        byte[] buffer = new byte[BUFFER_SIZE];

        while (running.get()) {
            try {
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                socket.receive(packet);

                // 处理接收到的数据包
                handlePacket(packet);

            } catch (IOException e) {
                if (running.get()) {
                    logger.error("接收数据包出错", e);
                }
            }
        }
    }

    /**
     * 处理接收到的数据包
     */
    private void handlePacket(DatagramPacket packet) {
        byte[] data = Arrays.copyOf(packet.getData(), packet.getLength());

        // 检查是否是心跳包
        if (isHeartbeat(data)) {
            handleHeartbeat(packet);
            return;
        }

        // 处理业务数据包
        processBusinessPacket(data, packet);
    }

    /**
     * 检查是否是心跳包
     */
    private boolean isHeartbeat(byte[] data) {
        if (data.length != HEARTBEAT_DATA.length) {
            return false;
        }
        return Arrays.equals(data, HEARTBEAT_DATA);
    }

    /**
     * 处理心跳包
     */
    private void handleHeartbeat(DatagramPacket packet) {
        try {
            // 发送心跳响应
            DatagramPacket response = new DatagramPacket(
                    HEARTBEAT_DATA,
                    HEARTBEAT_DATA.length,
                    packet.getAddress(),
                    packet.getPort()
            );
            socket.send(response);
            logger.debug("已响应心跳检测，来自: {}:{}",
                    packet.getAddress().getHostAddress(), packet.getPort());
        } catch (IOException e) {
            logger.error("发送心跳响应失败", e);
        }
    }

    /**
     * 处理业务数据包
     */
    private void processBusinessPacket(byte[] data, DatagramPacket packet) {
        // 这里处理实际的业务逻辑
        logger.info("收到业务数据包，大小: {} 字节，来自: {}:{}",
                data.length, packet.getAddress().getHostAddress(), packet.getPort());
    }

    /**
     * 停止服务器
     */
    public void stop() {
        running.set(false);
        if (socket != null && !socket.isClosed()) {
            socket.close();
        }
        logger.info("UDP后端服务器已停止，端口: {}", port);
    }

    /**
     * 启动示例
     */
    public static void main(String[] args) {
        if (args.length < 1) {
            System.out.println("Usage: java UdpBackendServer <port>");
            System.exit(1);
        }

        int port = Integer.parseInt(args[0]);

        try {
            UdpBackendServer server = new UdpBackendServer(port);
            server.start();

            // 添加关闭钩子
            Runtime.getRuntime().addShutdownHook(new Thread(server::stop));

            // 保持主线程运行
            Thread.currentThread().join();

        } catch (Exception e) {
            logger.error("服务器启动失败", e);
            System.exit(1);
        }
    }
} 